package com.sh.data.engine.domain.api.run;

import cn.hutool.core.convert.Convert;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.sh.data.engine.common.enumDefinition.DataApiCallStatusEnum;
import com.sh.data.engine.domain.api.model.domain.DataApiCallRecordDomain;
import com.sh.data.engine.domain.api.model.domain.DataApiRegisterDomain.ApiHttpAuthDomain;
import com.sh.data.engine.domain.api.model.domain.DataApiRegisterDomain.ApiHttpRequestBodyDomain;
import com.sh.data.engine.domain.api.model.domain.DataApiRegisterDomain.ApiHttpRequestHeaderDomain;
import com.sh.data.engine.domain.api.model.domain.DataApiTaskResultDomain;
import com.sh.data.engine.domain.api.model.domain.rest.DataApiRegisterTaskConfigInfoDomain;
import com.sh.data.engine.domain.api.util.DataApiUtil;
import com.sh.data.engine.domain.integration.api.http.model.param.ApiHttpAuthParam;
import com.sh.data.engine.domain.integration.api.http.model.param.ApiHttpRequestBodyParam.FormParam;
import com.sh.data.engine.domain.integration.api.http.model.param.ApiHttpRequestHeaderParam;
import com.sh.data.engine.domain.integration.api.http.service.ApiHttpService;
import com.sh.data.engine.domain.util.ConvertUtil;
import com.sh.data.engine.domain.util.TLSUtil;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.time.DateFormatUtils;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @auther: zigui.zdf
 * @description: 注册API执行器
 * @date: 2021/3/5 15:39
 */
public class DataApiRegisterTaskExecutor extends DataApiTaskExecutor<Map<String, String>> {

    private DataApiRegisterTaskConfigInfoDomain registerTaskConfigInfo;

    private ApiHttpService apiHttpService = SpringUtil.getBean(ApiHttpService.class);

    protected DataApiRegisterTaskExecutor(
        DataApiCallRecordDomain apiRecord,
        DataApiRegisterTaskConfigInfoDomain taskConfig,
        Map<String, String> params,
        Long id) {
        super(apiRecord, taskConfig, params, id);

        this.registerTaskConfigInfo = taskConfig;

        //    if (null == this.contentType) {
        //      this.contentType = 0;
        //    }
    }

    @Override
    protected Boolean checkTaskConfig() {
        Boolean checkPass = true;

        List<String> logs = Lists.newArrayList();
        String httpRequestMethod = registerTaskConfigInfo.getHttpRequestMethod();
        if (StringUtils.isBlank(httpRequestMethod)) {
            String log =
                String.format(
                    "[%s] protocol is blank", DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"));
            logs.add(log);
            checkPass = false;
        }
        String url = registerTaskConfigInfo.getUrl();
        if (StringUtils.isBlank(url)) {
            String log =
                String.format("[%s] url is blank", DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"));
            logs.add(log);
            checkPass = false;
        }

        //    if (StringUtils.isBlank(method)) {
        //      String log =
        //          String.format("[%s] method is blank", DateFormatUtils.format(new Date(),
        // "HH:mm:ss.SSS"));
        //      logs.add(log);
        //      checkPass = false;
        //    }

        if (!checkPass) {
            DataApiUtil.writeLog(this.apiRecord, id, logs);
        }

        return checkPass;
    }

    @Override
    protected DataApiTaskResultDomain doRun() throws Exception {

        //    if (!path.startsWith("/")) {
        //      path = "/" + path;
        //    }

        ApiHttpAuthDomain apiHttpAuthDomain = registerTaskConfigInfo.getApiHttpAuthDomain();
        ApiHttpRequestBodyDomain apiHttpRequestBodyDomain =
            registerTaskConfigInfo.getApiHttpRequestBodyDomain();
        ApiHttpRequestHeaderDomain apiHttpRequestHeaderDomain =
            registerTaskConfigInfo.getApiHttpRequestHeaderDomain();

        ApiHttpAuthParam auth = Convert.convert(ApiHttpAuthParam.class, apiHttpAuthDomain);

        ApiHttpRequestHeaderParam requestHeader =
            Convert.convert(ApiHttpRequestHeaderParam.class, apiHttpRequestHeaderDomain);

        ApiHttpRequestBodyDomain requestBody =
            Convert.convert(ApiHttpRequestBodyDomain.class, apiHttpRequestBodyDomain);

        String contentType = "";
        String rawJson = "";
        List<FormParam> formParams = null;

        if (StringUtils.equalsIgnoreCase(registerTaskConfigInfo.getHttpRequestMethod(), "POST")) {
            contentType = (null != requestBody) ? requestBody.getContentType() : "";
            rawJson = (null != requestBody) ? requestBody.getBody() : "";
            formParams =
                ConvertUtil.copyProperties(
                    (null != requestBody) ? requestBody.getFormParams() : null, FormParam.class);
        }

        Request request =
            apiHttpService.buildRequest(
                registerTaskConfigInfo.getUrl(),
                registerTaskConfigInfo.getHttpRequestMethod(),
                auth,
                requestHeader,
                contentType,
                formParams,
                rawJson);

        OkHttpClient httpClient =
            new OkHttpClient.Builder()
                .readTimeout(10, TimeUnit.SECONDS)
                .sslSocketFactory(TLSUtil.createSSLSocketFactory(), new TLSUtil.TrustAllManager())
                .hostnameVerifier(new TLSUtil.TrustAllHostnameVerifier())
                .build();

        List<String> logs = Lists.newArrayList();

        String log1 =
            String.format(
                "[%s] calling request : [%s]",
                DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"), request.toString());
        logs.add(log1);

        long s = System.currentTimeMillis();

        try (Response response = httpClient.newCall(request).execute()) {

            String log2 =
                String.format(
                    "[%s] call finished, task time : [%s]ms,response : [%s]",
                    DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"),
                    (System.currentTimeMillis() - s),
                    response.toString());
            logs.add(log2);

            try {
                Object output;
                String result = new String(response.body().bytes());

                try {
                    output = JSON.parse(result);
                } catch (Exception ignore) {
                    output = request;
                }

                return DataApiTaskResultDomain.builder()
                    .status(DataApiCallStatusEnum.SUCCESS.getStatus())
                    .output(output)
                    .build();
            } catch (IOException e) {
                String log3 =
                    String.format(
                        "[%s] parse body error, %s",
                        DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"),
                        ExceptionUtils.getFullStackTrace(e));
                logs.add(log3);

                throw e;
            }

        } catch (InterruptedIOException e) {
            String log4 =
                String.format(
                    "[%s] request timeout, %s",
                    DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"),
                    ExceptionUtils.getFullStackTrace(e));
            logs.add(log4);

            return DataApiTaskResultDomain.builder()
                .status(DataApiCallStatusEnum.TIMEOUT.getStatus())
                .build();

        } finally {
            httpClient.connectionPool().evictAll();

            DataApiUtil.writeLog(apiRecord, id, logs);
        }
    }

    private String urlEncoderText(String text) {
        if (StringUtils.isBlank(text)) {
            return StringUtils.EMPTY;
        }
        try {
            text = URLEncoder.encode(text, "utf-8");
        } catch (UnsupportedEncodingException e) {
        }
        return text;
    }
}
/**
 * 获取get请求参数
 *
 * @return
 */
